Skip to content

ci(test): temporarily raise Test Core (N/6) timeout-minutes 30 -> 45, with its revert condition inline - #16451

Merged
huangyiirene merged 1 commit into
mainfrom
claude/issue-16445-raise-test-core-shard-wall
Sep 7, 2026
Merged

ci(test): temporarily raise Test Core (N/6) timeout-minutes 30 -> 45, with its revert condition inline#16451
huangyiirene merged 1 commit into
mainfrom
claude/issue-16445-raise-test-core-shard-wall

Conversation

@huangyiirene

@huangyiirene huangyiirene commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Fixes #16445

One line moves, plus the expiry that keeps it temporary rather than permanent by forgetting. In .github/workflows/ci.yml, the test job — name: Test Core (${{ matrix.shard }}/6) — goes timeout-minutes: 3045.

This executes the maintainer directive recorded on the card, verbatim: 「临时抬墙」. It is not a design proposal.

What moved — and the proof that nothing else did

The raised value now sits at line 316; it was at line 295 on the base commit bf45e62ce, and the 21 comment lines added above it account for the whole shift. Because line numbers drift, the census below is keyed on the job, so a second changed value could not hide behind the offset.

job job name before after
filter Detect changed paths 10 10
test Test Core (N/6) 30 45
test-gate Test Core 10 10
temporal-conformance Temporal Conformance (live PG + MySQL) 30 30
dogfood Dogfood Regression Gate (N/3) 30 30
dogfood-verify Dogfood Verify CLI 20 20
dogfood-gate Dogfood Regression Gate 10 10
build-core Build Core 30 30
build-docs Build Docs 30 30
console-pin Console Pin Gate 45 45

Ten occurrences before, ten after — nothing added, nothing removed. Diffing the two job value censuses yields exactly one changed line:

2c2
< test: 30
---
> test: 45

The whole diff is 1 file changed, 22 insertions(+), 1 deletion(-): one value line and twenty-one comment lines, in one file. scripts/test-shard-timings.json is untouched, the shard count and matrix are untouched, no vitest config is touched, no test is skipped or quarantined, and no cancelled shard was re-run — those were different options and none of them was the one chosen.

Why 45, and why it is an instrument as well as an unblock

Test Core (5/6) has been killed at the 30-minute wall repeatedly today — 12+ observations at 30:16 ×7 · 30:17 ×2 · 30:18 ×2 · 30:21, with every other job in every one of those runs green.

Those are not measurements of the shard. They are readings of timeout-minutes: the true duration is >= 30:16, censored and unbounded above. The only uncensored shard-5 readings are 25:32 and 27:36, and shard 6/6 — never killed — has been seen at 28:56. So the observed green band is 25:30–28:56 against a 30:00 wall: roughly a minute of margin at the top.

45 is not arbitrary. The same file already runs console-pin at timeout-minutes: 45, so it is a value this repo already tolerates on a required job, and it is approached from below rather than exceeded.

The second effect is the more valuable one: while the wall stands at 30, the shard timings cannot be re-derived from CI history, because every tail observation is censored. Raising it produces the real durations, which is precisely the input the shard rebalance needs before anyone edits scripts/test-shard-timings.json. That rebalance is not addressed here and #16173 remains open.

The revert condition lives in the file, not only in this PR

A temporary raise with no expiry written beside it becomes permanent by forgetting. The new value therefore carries an inline block that names #16173 as the reason, states plainly that the raise is temporary, and states the revert condition explicitly: back to 30 once #16173 lands its shard rebalance.

The pre-existing rationale paragraph above the value is left byte-for-byte intact — it argues for 30, and it is exactly the argument the revert must satisfy — but it would otherwise read as a description of the current value, so the new block says in so many words that the paragraph above describes the value this line must return to, not the value it currently carries. The stall guard on the test steps remains the primary hang detector throughout; this backstop is loose only for that window.

Governed surface: NO — measured from the guard, not assumed from prose

Read from the guard's own source rather than from the AGENTS.md list. scripts/pm/check-governed-queue-guard.mjs states no surface list of its own — it imports GOVERNED_SURFACES from scripts/pm/check-governed-merges.mjs, and its --self-test pins that with the case this-file-restates-no-surface-list. Running the register and the seat-side pre-arm predicate against this PR's final file list:

$ node scripts/pm/check-governed-merges.mjs --test .github/workflows/ci.yml
governed-surface predicate: 0 of 1 path(s) hit the register (5 surfaces, repo-agnostic).
  NOT governed — ordinary queue landing applies to a PR with exactly this file list.
EXIT=0        (EXIT_TEST_NOT_GOVERNED = 0; EXIT_TEST_GOVERNED would be 3)

Today's register is docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md, printed from the module rather than recalled. .github/workflows/** is not among them, and a control path .claude/x.md run through the same predicate does hit, so the negative reading is not a broken matcher answering "no" to everything. The Governed Surface Queue Guard check on this PR has since concluded success, which is the guard itself agreeing on this PR's own file list.

This PR takes the ordinary merge-queue path. It is left as a draft for the PM regardless; flipping it ready and enqueueing is the PM's call, not this seat's.

Clause ②: no — confirmed, not inherited

Confirmed independently of the claim comment's declaration. The diff changes a CI job's wall-clock backstop. It touches nothing under packages/spec/src/**, no *.zod.ts contract schema, no error-code ledger, no export, and no accept-set: no published contract accepts or rejects anything differently after this PR, and no public surface widens. Clause ② is about the published contract surface, so it reads no.

Changeset: not owed — skip-changeset

Nothing in this diff publishes. The change set is one workflow file; no package's published surface moves, so there is no released package for a changeset to describe, and a patch entry here would announce a release that does not exist. That is the textbook case the label exists for, and the label is a real mechanism in this repo — changeset-check in .github/workflows/pr-automation.yml is exempted by the job-level if: plus its two live label re-reads, with no path-based auto-exemption to fall back on. The label is applied to this PR as an authoring step rather than left to CI, and the Check Changeset run on this PR concluded success.

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 38 families for this change set, and --ran reconciles clean:

✓ dispatch-gates --ran: 38 derived famil(ies) accounted for — 38 run, 0 NOT-MEASURED.

36 green, exit 0. Two returned exit 3, PREREQUISITE NOT MET — reported as NOT MEASURED, never as green and never as red:

  • pnpm check:dts-closure — "Not one of the 79 workspace package(s) under . has a dist/". Its own text: "This is NOT a pass and NOT a finding."
  • pnpm check:dual-build-cjs-loads — "this gate reads built output, and some package has no dist/. Nothing was measured."

Both read dist/, and this diff changes no package source, so a closure build would have them measure something no path here can move. CI builds the closure and runs them.

The two load-bearing families for this specific change both genuinely read the raised value rather than skipping:

check-stall-guard-budget: OK (32 workflow file(s), 56 job(s), 611 step(s), 7 guard-wrapped step(s);
every effective cap clears its job budget by at least one stall window).
  .github/workflows/ci.yml:658  job `test` step `Run this shard's tests`
      window 10m (explicit) · cap 20m (2x window) · budget 45m (job timeout-minutes) · slack 25m

The budget 45m is this PR's value being read back, and the slack on the guarded step goes 10m → 25m. pnpm check:stall-guard-headroom is green but runs --self-test only, so it grades the checker's fixtures, not this diff; it is not PR clearance in either direction. pnpm check:required-contexts, pnpm check:shard-attestation, pnpm check:ci-filter-parity and pnpm check:nul-bytes are green on the real diff.

The file also parses: yaml.safe_load returns jobs.test['timeout-minutes'] == 45 as an int, with the matrix still shard: [1, 2, 3, 4, 5, 6] and 10 jobs.

The self-test fired — and its answer is "not from this PR"

This PR's own CI run executes with the raised wall, and all six Test Core shards went green. But their durations are not shard measurements, and reporting them as such would be a phantom reading of exactly the kind this card is about. Test Core (5/6) completed in 54s (02:05:18Z → 02:06:12Z), and its own log says why:

shard 5/6: 0/0 items (0 of them file-level slices of 0 package(s)), 0.0s predicted
No packages on this shard — nothing to test.
No test log — the test step did not get far enough to produce one.
Attested: test-5-of-6 ran to completion with every step green

A .github/workflows/**-only diff affects zero packages, so the partitioner scheduled zero items onto every shard. That 54s is fixed per-shard overhead — checkout, pnpm/Turbo cache restore, install, attestation — and nothing else.

This PR un-censors nothing, and the shard-timing work should not read a number from it. The raise is still the instrument, but it only reads on a PR whose diff actually schedules packages onto shard 5. The first uncensored shard-5 duration will come from the next such PR to run against this workflow — that is where the rebalance should take its input, and it is the reason this raise wants to stay in place until then.

Shard 5/6 keeps hitting the 30-minute wall, so every tail observation is a
reading of the wall rather than of the shard: the true duration is censored
and unbounded above. Raising the backstop both unblocks the job and
un-censors the durations the shard rebalance needs before it can be derived.

The new value carries its revert condition inline, next to the value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
@huangyiirene huangyiirene added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed ci/cd labels Sep 7, 2026 — with Claude
@huangyiirene
huangyiirene marked this pull request as ready for review September 7, 2026 02:12
@huangyiirene
huangyiirene added this pull request to the merge queue Sep 7, 2026
Merged via the queue into main with commit 8047911 Sep 7, 2026
44 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-16445-raise-test-core-shard-wall branch September 7, 2026 03:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[temporary] raise Test Core (N/6) timeout-minutes 30 → 45 while #16173's shard balance is unfixed — and un-censor the readings that #16173 needs

2 participants